package cc.chinagps.gateway.unit.eg.upload;

import cc.chinagps.gateway.StartServer;
import cc.chinagps.gateway.cache.DataCache;
import cc.chinagps.gateway.cache.ICache;
import cc.chinagps.gateway.db.ConnectionManager;
import cc.chinagps.gateway.log.LogManager;
import cc.chinagps.gateway.unit.eg.upload.bean.DeviceLog;
import cc.chinagps.gateway.unit.eg.upload.bean.EGDevice;
import cc.chinagps.gateway.unit.eg.util.EGTimeFormatUtil;
import cc.chinagps.gateway.util.IOUtil;
import cc.chinagps.gateway.util.SystemConfig;
import org.apache.log4j.Logger;

import java.sql.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DeviceInfoManager {
    private Logger logger_debug = Logger.getLogger(LogManager.LOGGER_NAME_DEBUG);
    private ICache<DeviceLog> logCache = new DataCache<>("deviceLog", 2000);
    private static final String sql = "insert into t_log_device(device_id,collect_time,log_info,receive_time) values(?,?,?,?)";
    private static final int BATCH_SIZE = 100;
    private Map<String, EGDevice> mcuChipMap = new ConcurrentHashMap<>();
    private Map<String, EGDevice> deviceIdMap = new ConcurrentHashMap<>();
    private Map<String, EGDevice> iccidMap = new ConcurrentHashMap<>();
    ICache<EGDevice> versionCache = new DataCache<>("versionCache", 2000);
    private boolean isFirstTime = true;
    private Timestamp updateTime;

    private boolean started = true;
    private Timestamp refreshTime;

    public boolean addLogInfo(DeviceLog deviceLog) {
        return logCache.addData(deviceLog);
    }

    public EGDevice getEGDevice(String mcuChipId) {
        return mcuChipMap.get(mcuChipId);
    }

    public EGDevice getDeviceByIccid(String iccid) {
        return iccidMap.get(iccid);
    }

    public EGDevice getDeviceById(String deviceId) {
        return deviceIdMap.get(deviceId);
    }

    public void startService() {
        new Thread(new SaveLogThread(logCache)).start();
        new RefreshMcuChipThread().start();
        //new RefreshDeviceThread().start();
        new RefreshFullDeviceThread().start();
        new SaveVersionThread().start();
    }

    public boolean addVersion(EGDevice version) {
        return versionCache.addData(version);
    }

    class SaveVersionThread extends Thread {
        @Override
        public void run() {
            while (true) {
                List<EGDevice> versions = versionCache.getData();
                for (EGDevice version : versions) {
                    String sql = "replace into t_ba_unit_version(call_letter,iccid,sw_version,sw_version_number,conf_param) " +
                            "values(?,?,?,?,?)";
                    Connection con = null;
                    PreparedStatement pst = null;
                    try {
                        con = ConnectionManager.openConnection();
                        con.setAutoCommit(false);
                        pst = con.prepareStatement(sql);
                        pst.setString(1, version.getDeviceId());
                        pst.setString(2, version.getIccid());
                        pst.setString(3, version.getSwVersion());
                        pst.setString(4, version.getSwVersionNO());
                        pst.setString(5, version.getConfParam());
                        pst.executeUpdate();
                        con.commit();
                    } catch (SQLException e) {
                        StartServer.instance.getUnitServer().exceptionCaught(e);
                    } finally {
                        IOUtil.closeDB(null, pst, con);
                    }
                }
            }
        }
    }

    private void loadNcuChipInfo() {
        String sql = "SELECT mcu_chip_id,chip_authorize_code FROM t_ba_mcu where update_time>?";
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            if (isFirstTime) {
                Date refreshDate = EGTimeFormatUtil.parseGMT8(SystemConfig.getDBProperties().getProperty("device.refresh.start.time", "20000101000000"));
                updateTime = new Timestamp(refreshDate.getTime());
            }
            con = ConnectionManager.openConnection();
            Timestamp tempTime = new Timestamp(System.currentTimeMillis());
            pst = con.prepareStatement(sql);
            pst.setTimestamp(1, updateTime);
            rs = pst.executeQuery();
            isFirstTime = false;
            updateTime = tempTime;
            int refreshNum = 0;
            while (rs.next()) {
                EGDevice egDevice = new EGDevice();
                String mcuChipId = rs.getString(1);
                String chipAuthCode = rs.getString(2);
                if (mcuChipId == null || chipAuthCode == null) {
                    continue;
                }
                refreshNum++;
                mcuChipId = mcuChipId.trim();
                egDevice.setMcuChipId(mcuChipId);
                egDevice.setChipAuthCode(chipAuthCode.trim());
                mcuChipMap.put(mcuChipId, egDevice);
            }
            logger_debug.debug("mcuChipMap refresh size:" + refreshNum);
        } catch (Exception e) {
            StartServer.instance.getUnitServer().exceptionCaught(e);
        } finally {
            IOUtil.closeDB(rs, pst, con);
        }
    }

    class RefreshMcuChipThread extends Thread {
        @Override
        public void run() {
            while (true) {
                loadNcuChipInfo();
                try {
                    Thread.sleep(120000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void loadFullDeviceInfo(){
        String sql = "SELECT call_letter,iccid FROM t_ba_unit";
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            con = ConnectionManager.openConnection();
            pst = con.prepareStatement(sql);
            rs = pst.executeQuery();
            int refreshNum = 0;
            while (rs.next()) {
                EGDevice egDevice = new EGDevice();
                String deviceId = rs.getString(1);
                String iccid = rs.getString(2);
                if (deviceId == null && iccid == null) {
                    continue;
                }
                refreshNum++;
                egDevice.setDeviceId(deviceId);
                egDevice.setIccid(iccid);
                if (deviceId != null) {
                    deviceIdMap.put(deviceId, egDevice);
                }
                if (iccid != null) {
                    iccidMap.put(iccid, egDevice);
                }
            }
            logger_debug.debug("full device refresh size:" + refreshNum);
        } catch (Exception e) {
            StartServer.instance.getUnitServer().exceptionCaught(e);
        } finally {
            IOUtil.closeDB(rs, pst, con);
        }
    }

    class RefreshFullDeviceThread extends Thread {
        @Override
        public void run() {
            while (true) {
                loadFullDeviceInfo();
                try {
                    Thread.sleep(StartServer.deviceRefreshInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void loadDeviceInfo() {
        String sql = "SELECT call_letter,iccid FROM t_ba_unit where update_time>?";
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            if (started) {
                Date refreshDate = EGTimeFormatUtil.parseGMT8(SystemConfig.getDBProperties().getProperty("device.refresh.start.time", "20000101000000"));
                refreshTime = new Timestamp(refreshDate.getTime());
            }
            con = ConnectionManager.openConnection();
            Timestamp tempTime = new Timestamp(System.currentTimeMillis());
            pst = con.prepareStatement(sql);
            pst.setTimestamp(1, refreshTime);
            rs = pst.executeQuery();
            started = false;
            refreshTime = tempTime;
            int refreshNum = 0;
            while (rs.next()) {
                EGDevice egDevice = new EGDevice();
                String deviceId = rs.getString(1);
                String iccid = rs.getString(2);
                if (deviceId == null && iccid == null) {
                    continue;
                }
                refreshNum++;
                egDevice.setDeviceId(deviceId);
                egDevice.setIccid(iccid);
                if (deviceId != null) {
                    deviceIdMap.put(deviceId, egDevice);
                }
                if (iccid != null) {
                    iccidMap.put(iccid, egDevice);
                }

            }
            logger_debug.debug("device refresh size:" + refreshNum);
        } catch (Exception e) {
            StartServer.instance.getUnitServer().exceptionCaught(e);
        } finally {
            IOUtil.closeDB(rs, pst, con);
        }
    }

    class RefreshDeviceThread extends Thread {
        @Override
        public void run() {
            while (true) {
                loadDeviceInfo();
                try {
                    Thread.sleep(StartServer.deviceRefreshInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class SaveLogThread implements Runnable {
        private ICache<DeviceLog> cache;

        public SaveLogThread(ICache<DeviceLog> logCache) {
            this.cache = logCache;
        }

        @Override
        public void run() {
            while (true) {
                List<DeviceLog> deviceLogs = cache.getData();
                Connection con = null;
                PreparedStatement pst = null;
                int batchCount = 0;
                try {
                    con = ConnectionManager.openConnection();
                    con.setAutoCommit(false);
                    pst = con.prepareStatement(sql);
                    for (int i = 0; i < deviceLogs.size(); i++) {
                        DeviceLog deviceLog = deviceLogs.get(i);
                        pst.setString(1, deviceLog.getDeviceId());
                        pst.setTimestamp(2, new Timestamp(deviceLog.getCollectTime()));
                        pst.setString(3, deviceLog.getLogInfo());
                        pst.setTimestamp(4, new Timestamp(deviceLog.getReceiveTime()));
                        pst.addBatch();
                        batchCount++;
                        if (batchCount >= BATCH_SIZE) {
                            pst.executeBatch();
                            con.commit();
                            batchCount = 0;
                        }
                    }
                    if (batchCount > 0) {
                        pst.executeBatch();
                        con.commit();
                    }
                } catch (Exception e) {
                    StartServer.instance.getUnitServer().exceptionCaught(e);
                } finally {
                    IOUtil.closeDB(null, pst, con);
                }
            }
        }
    }
}
